/**
 * redis 数据管理
 */

#ifndef COMMON_DATA_REDIS_H
#define COMMON_DATA_REDIS_H

#include <sw/redis++/redis.h>

#include <memory>
#include <string>

namespace chat {
/**
 * @brief 工厂类：创建一个redis客户端
 */
class RedisClientFactory {
   public:
    /**
     * @param ip[in]: redis服务器ip
     * @param port[in]: redis服务器端口
     * @param db[in]: 库的编号，默认为0
     * @param keep_alive[in]: 是否设置长连接保活
     */
    static std::shared_ptr<sw::redis::Redis> create(const std::string& ip,
                                                    const uint16_t port,
                                                    const int db,
                                                    const bool keep_alive);
};

/**
 * @brief 用户会话管理类 [会话id - 用户id]
 *        - 当用户进行登陆的时候，为其分配一个会话id，并存储到redis
 *        - 当用户进行操作的时候，需要附上自己的会话id，通过会话id查找键值对
 */
class Session {
   public:
    Session(const std::shared_ptr<sw::redis::Redis>& client)
        : client_(client) {}

    bool append(const std::string& session_id, const std::string& uid);
    bool remove(const std::string& session_id);
    sw::redis::OptionalString uid(const std::string& session_id);

   private:
    std::shared_ptr<sw::redis::Redis> client_ = nullptr;
};

using SessionPtr = std::shared_ptr<Session>;

/**
 * @brief 用户的登陆状态管理 [用户id - 随机状态码]
 * - 当用户进行第一次登陆的时候，为其分配一个状态码，表示其已经登陆
 * - 当用户再进行登录的时候，就会通过查找对应的uid是否存在状态码，来避免重复登陆
 * - 当用户断开连接，就需要将这一键值对删除
 */
class Status {
   public:
    Status(const std::shared_ptr<sw::redis::Redis>& client) : client_(client) {}

    bool append(const std::string& uid);
    bool remove(const std::string& uid);
    bool exists(const std::string& uid);

   private:
    std::shared_ptr<sw::redis::Redis> client_ = nullptr;
};

using StatusPtr = std::shared_ptr<Status>;

/**
 * @brief 验证码管理 [验证码id - 验证码code]
 * - 用户获取短信验证码时，生成验证码id，并进行redis管理，同时设置租约时长
 * - 手机号注册/登录/修改绑定手机时，就要进行验证码及id验证
 * - 使用完验证码，或验证码过期时，就需要将其从redis中删除
 *
 */
class Codes {
   public:
    Codes(const std::shared_ptr<sw::redis::Redis>& client) : client_(client) {}

    bool append(const std::string& code_id, const std::string& code,
                const std::chrono::milliseconds& t);
    bool remove(const std::string& code_id);
    sw::redis::OptionalString code(const std::string& code_id);

   private:
    std::shared_ptr<sw::redis::Redis> client_ = nullptr;
};

using CodesPtr = std::shared_ptr<Codes>;

}  // namespace chat

#endif  // COMMON_DATA_REDIS_H